#region Copyright (c) 2003-2004 ComponentGo!
/*
*********************************************************************
*                                                                   *
*       ComponentGo! Component Library                              *
*                                                                   *
*       Copyright (c) 2003-2004 ComponentGo!                        *
*       ALL RIGHTS RESERVED                                         *
*                                                                   *
*********************************************************************
*/
#endregion

using System;
using System.Reflection;
using System.Globalization;
using System.Drawing;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;

namespace ComponentGo.Calendars
{
	/// <summary>
	/// A class representing a set of appointments.
	/// </summary>
	/// <remarks>
	/// Class allows for grouping appointment in a resource and their appropriate 
	/// display in a control.<see cref="ResourceScheduler"/>.
	/// </remarks>
	[TypeConverter(typeof(Resource.Converter))]
	[DesignTimeVisible(false)]
	[System.Runtime.InteropServices.ComVisible(true)]
	public class Resource
	{
		#region Converter

		/// <summary>
		/// A class supporting edits of an resource in a Visual Studio environment.
		/// </summary>
		internal class Converter : ExpandableObjectConverter {

			/// <summary>
			/// Determines a possibility of converting an resource to an object <c>InstanceDescriptor</c>.
			/// </summary>
			/// <param name="ctx">Conversion context.</param>
			/// <param name="t">A type a conversion can be performed to.</param>
			/// <returns>Returns <c>true</c> if <paramref name="t"/> is an <c>InstanceDescriptor</c>.</returns>
			public override bool CanConvertTo(ITypeDescriptorContext ctx, Type t) {
				if (t==typeof(InstanceDescriptor)) return true;
				return base.CanConvertTo(ctx, t);
			}

			static readonly Type [] constPars1 = new Type[] { typeof(string) };
			static readonly Type [] constPars2 = new Type[] { typeof(string), typeof(Color), typeof(bool) };

			/// <summary>
			/// Converts an resource to an object <c>InstanceDescriptor</c>. 
			/// </summary>
			/// <param name="context">Conversion context.</param>
			/// <param name="culture">Conversion language.</param>
			/// <param name="value">Converted object of type <see cref="Resource"/>.</param>
			/// <param name="destinationType">A type a conversion is to be performed to.</param>
			/// <returns>Converted object of type <c>InstanceDescriptor</c>.</returns>
			public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
				if (destinationType==typeof(InstanceDescriptor)) {
					Resource resource = (Resource)value;
					Type [] types;
					object [] pars;
					if (resource.BackColor==Color.Empty && !resource.ForceEmpty) {
						types = constPars1;
						pars = new object[] { resource.Text };
					}
					else {
						types = constPars2;
						pars = new object[] { resource.Text, resource.BackColor, resource.ForceEmpty };
					}

					ConstructorInfo ci = typeof(Resource).GetConstructor(types);
					return new InstanceDescriptor(ci, pars);
				}

				return base.ConvertTo(context, culture, value, destinationType);
			}

		}

		#endregion

		#region General

		/// <summary>
		/// Constructs a resource object initialising its properties to default values.
		/// </summary>
		public Resource() {
		}

		/// <summary>
		/// Constructs a resource object initialising its properties to default values.
		/// </summary>
		/// <remarks>
		/// Allows for initialising a <see cref="Text"/> property to a given value.
		/// </remarks>
		/// <param name="text">A value initialising a <see cref="Text"/> property.</param>
		public Resource(string text) {
			this.text = text;
		}

		/// <summary>
		/// Contructs a resource object initialising it with values supplied.
		/// </summary>
		/// <param name="text">A value initialising a <see cref="Text"/> property.</param>
		/// <param name="backColor">A default value of a <see cref="BackColor"/> property.</param>
		public Resource(string text, Color backColor) : this(text) {
			this.backColor = backColor;
		}

		/// <summary>
		/// Contructs a resource object initialising it with values supplied.
		/// </summary>
		/// <param name="text">A value initialising a <see cref="Text"/> property.</param>
		/// <param name="backColor">A default value of a <see cref="BackColor"/> property.</param>
		/// <param name="forceEmpty">A default value of a <see cref="ForceEmpty"/> property.</param>
		public Resource(string text, Color backColor, bool forceEmpty) : this(text, backColor) {
			this.forceEmpty = forceEmpty;
		}

		/// <summary>
		/// Returns a textual representation of an resource.
		/// </summary>
		/// <returns>Textual representation of an resource.</returns>
		/// <remarks>
		/// A string consisting of a textual description of an resource <see cref="Text"/>.
		/// </remarks>
		public override string ToString() {
			return Text;
		}

		#endregion

		#region Properties

		string text = "";

		/// <summary>
		/// A resource title displayed in a control.
		/// </summary>
		[Category("Appearance")]
		[Description("A resource title displayed in a control.")]
		public string Text {
			get { return text; }
			set {
				if (value==null) value = "";
				if (text==value) return;
				text = value;
				change();
			}
		}

		Color backColor = Color.Empty;

		/// <summary>
		/// Background color of a rectangle an resource is displayed in.
		/// </summary>
		[Category("Appearance")]
		[Description("Background color of a rectangle an resource is displayed in.")]
		public Color BackColor {
			get { return backColor; }
			set {
				if (backColor==value) return;
				backColor = value;
				change();
			}
		}

		bool forceEmpty = false;

		/// <summary>
		/// Prevent dragging an appointment to a resource area.
		/// <seealso cref="BaseCalendar.QueryAppointmentDrag"/>
		/// </summary>
		[Category("Behavior")]
		[Description("Prevent dragging an appointment to a resource area.")]
		public bool ForceEmpty {
			get { return forceEmpty; }
			set {
				forceEmpty = value;
			}
		}

		#region Tag

		object tag = null;

		/// <summary>
		/// Gets or sets an object that contains data to associate with the category.
		/// </summary>
		/// <value>
		/// An object that contains information that is associated with the category.
		/// </value>
		/// <remarks>
		/// The <b>Tag</b> property can be used to store any object that you want 
		/// to associate with an category. Although you can store any item, 
		/// the <b>Tag</b> property is typically used to store string information about 
		/// the item such as a unique identifier or the index position of the 
		/// item's data in a database.
		/// </remarks>
		[Browsable(false)]
		public object Tag {
			get { return tag; }
			set { tag = value; }
		}

		#endregion

		#endregion

		#region Implementation

		void change() {
			coll.resync(false);
		}

		ResourceCollection coll = null;

		internal void attach(ResourceCollection coll) {
			if (this.coll!=null)
				throw new InvalidOperationException("Can not add resource object multiple times to ResourceCollection");
			this.coll = coll;
		}

		internal void detach() {
			this.coll = null;
		}

		#endregion
	}
}
